//
//  NSObject+JsonToModel.m
//  ruying
//
//  Created by yqh on 2019/2/23.
//  Copyright © 2019年 林伟钦. All rights reserved.
//

#define FCValidKeys @{\
    @"id" : @"ID",\
}

#import "NSObject+JsonToModel.h"

@implementation NSObject (JsonToModel)

+ (id)objFromJSON:(id)json {
    if (json) {
        
        // NSDictionary --> Model
        if ([json isKindOfClass:[NSDictionary class]]) {
            
            NSDictionary *dic = (NSDictionary *)json;
            id obj = [self new];
            
            [self updateModel:obj withDic:dic];
            
            return obj;
        }
        // NSArray --> Models
        else if ([json isKindOfClass:[NSArray class]]) {
            
            NSArray *dics = (NSArray *)json;
            NSMutableArray *objs = [NSMutableArray array];
            
            id obj = nil;
            for (NSDictionary *dic in dics) {
                //数组中必须是 NSDictionary，且不能是空 NSDictionary
                if ([dic isKindOfClass:[NSDictionary class]] && dic.allKeys.count > 0) {
                    obj = [self objFromJSON:dic];
                    if (obj) {
                        [objs addObject:obj];
                    }
                }
            }
            
            return objs;
        }
        // Others
        else {
            return nil;
        }
    }
    return nil;
}
+ (instancetype)modelFromDic:(NSDictionary<NSString *, id> *)dic {
    return [self objFromJSON:dic];
}
+ (NSArray<id> *)modelsFromArr:(NSArray<NSDictionary *> *)arr {
    return [self objFromJSON:arr];
}

+ (void)updateModel:(id)obj withDic:(NSDictionary *)dic {
    
    if (dic.allKeys.count > 0) {
        
        id theObj = obj;
        if (theObj == nil) {
            theObj = [self new];
        }
        
        Class aClass = [self class];
        
        objc_property_t aProperty = NULL;
        id value = nil;
        NSString *attrStr;
        
        for (NSString *key in dic.allKeys) {
            
            NSString *KEY = ([FCValidKeys.allKeys containsObject:key] ? FCValidKeys[key] : key);
            
            aProperty = class_getProperty(aClass, [KEY UTF8String]);
            if (aProperty != NULL) {
                
                attrStr = [NSString stringWithCString:property_getAttributes(aProperty) encoding:NSUTF8StringEncoding];
                
                //Foundation类型的属性
                if ([self isFoundationClass:attrStr]) {
                    //NSArray属性
                    if ([attrStr containsString:@"NSArray"] || [attrStr containsString:@"NSMutableArray"]) {
                        
                        if ([dic[key] isKindOfClass:[NSArray class]]) {
                            value = [NSMutableArray arrayWithArray:dic[key]];
                        } else {
                            value = @[];
                        }
                    }
                    //NSDictionary属性
                    else if ([attrStr containsString:@"NSDictionary"]) {
                        value = dic[key];
                    }
                    //其他Foundation类型的属性，如：NSURL,NSDate,NSString...  ==> 全部转成 NSString
                    else {
                        value = [self checkObj:dic[key]];
                    }
                }
                //自定义类型的属性
                else {
                    
                    NSString *className = [self classNameFromPropertyAttrStr:attrStr];
                    Class cusClass = NSClassFromString(className);
                    NSDictionary *tmpDic = dic[key];
                    
                    if (cusClass && [tmpDic isKindOfClass:[NSDictionary class]] && tmpDic.allKeys.count > 0) {
                        value = [cusClass new];
                        [cusClass updateModel:value withDic:tmpDic];
                    }
                }
                
                [theObj setValue:value forKey:KEY];
            }
        }
    }
}
+ (NSString *)classNameFromPropertyAttrStr:(NSString *)pAttrStr {
    
    //T@"NSString",C,N,V_userid
    
    NSArray *comps = [pAttrStr componentsSeparatedByString:@","];  //  T@"NSString"    C   N   V_userid
    NSString *tmpStr = [comps firstObject];
    NSString *className = [tmpStr stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"T@\""]];
    
    return className;
}
+ (BOOL)isFoundationClass:(NSString *)className {
    __block BOOL flag = NO;
    __block NSString *aClass;
    NSArray *classArr = @[ @"NSArray", @"NSMutableArray", @"NSDictionary", @"NSURL", @"NSDate", @"NSValue", @"NSData", @"NSError", @"NSString", @"NSAttributedString",@"NSNumber" ];
    [classArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        aClass = (NSString *)obj;
        if ([className containsString:aClass]) {
            flag = YES;
            *stop = YES;
        }
    }];
    return flag;
}

- (NSMutableDictionary *)createDictionayFromModelProperties {
    NSMutableDictionary *propsDic = [NSMutableDictionary dictionary];
    unsigned int outCount, i;
    // class:获取哪个类的成员属性列表
    // count:成员属性总数
    // 拷贝属性列表
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    for (i = 0; i<outCount; i++)
    {
        objc_property_t property = properties[i];
        const char* char_f = property_getName(property);
        // 属性名
        NSString *propertyName = [NSString stringWithUTF8String:char_f];
        // 属性值
        id propertyValue = [self valueForKey:(NSString *)propertyName];
        // 设置KeyValues
        if (propertyValue) [propsDic setObject:propertyValue forKey:propertyName];
        
    }
    // 需手动释放 不受ARC约束
    free(properties);
    return propsDic;
}

- (BOOL)isValidJSON {
    if ([self isKindOfClass:[NSDictionary class]] || [self isKindOfClass:[NSArray class]]) {
        return YES;
    }
    return NO;
}

+ (BOOL)isValidJSON:(id)obj {
    if ([obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSArray class]]) {
        return YES;
    }
    return NO;
}

+ (NSString *)checkObj:(NSObject *)obj {
    if (obj) {
        if ([obj isKindOfClass:[NSString class]]) {
            return (NSString *)obj;
        } else if ([obj isKindOfClass:[NSNull class]]) {
            return @"";
        } else {
            return [NSString stringWithFormat:@"%@", obj];
        }
    }
    return @"";
}

@end
